home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / kernel / ui.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-02  |  36.1 KB  |  1,347 lines  |  [TEXT/KAHL]

  1. /* Graphics support not specific to any Xconq interface.
  2.    Copyright (C) 1993, 1994, 1995 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. /* This file includes some very general graphics-related functionality
  10.    that interfaces can (but are not required to) use.  For instance,
  11.    the size and shapes of hex cells have been precalculated to provide
  12.    a reasonable appearance at several magnifications.  Note that some
  13.    of the algorithms in this file are abstracted from code that has been
  14.    tuned and tweaked over many years, so it is strongly recommended that
  15.    all new graphical interfaces use these. */
  16.  
  17. #include "conq.h"
  18. extern UnitVector *actionvector;
  19. #include "imf.h"
  20. #include "ui.h"
  21.  
  22. #ifdef MAC /* temporary */
  23. #include <Values.h>
  24. #include <Types.h>
  25. #include <Resources.h>
  26. #endif
  27.  
  28. static ImageFamily *get_generic_images PROTO ((Side *side, char *name, 
  29.                           void (*interp_hook)(ImageFamily *imf),
  30.                           void (*load_hook)(ImageFamily *imf)));
  31.  
  32. /* The two games that should be always be available. */
  33.  
  34. char *first_game_name = "intro";
  35.  
  36. char *second_game_name = "standard";
  37.  
  38. /* The following magical arrays set all the sizes at each magnification. */
  39.  
  40. /* This is the basic cell size. */
  41.  
  42. short mags[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
  43.  
  44. /* These give the total dimensions of each hex cell, plus the vertical
  45.    distance center-to-center.  This is all carefully calculated to make
  46.    the cells overlap perfectly at each different magnification, assuming
  47.    that the icons have the right shape and size. */
  48.  
  49. short hws[] = { 1, 2, 4, 8, 24, 44, 88, 174 };
  50. short hhs[] = { 1, 2, 4, 8, 26, 48, 96, 192 };
  51. short hcs[] = { 1, 2, 4, 8, 20, 37, 75, 148 };
  52.  
  53. /* The sizes of the unit subcells.  This is available drawing area, exact
  54.    unit icon sizes depends on what's available. */
  55.  
  56. short uhs[] = { 1, 2, 3, 8, 16, 32, 64, 128 };
  57. short uws[] = { 1, 2, 3, 8, 16, 32, 64, 128 };
  58.  
  59. /* Widths of borders and connections (0 implies don't draw at all). */
  60.  
  61. /* Full border width. */
  62.  
  63. short bwid[NUMPOWERS]  = { 0, 0, 1, 1, 3, 5, 7, 9 };
  64.  
  65. /* Half-width, for narrower inset borders. */
  66.  
  67. short bwid2[NUMPOWERS] = { 0, 0, 1, 1, 2, 3, 4, 5 };
  68.  
  69. /* Full connection width. */
  70.  
  71. short cwid[NUMPOWERS] = { 0, 0, 1, 1, 3, 5, 7, 9 };
  72.  
  73. /* Coordinates of the hex borders. */
  74. /* Note that array has extra column so don't need to wrap index. */
  75.  
  76. short bsx[NUMPOWERS][7] = {
  77.     { 0 },
  78.     { 0 },
  79.     {  2,   4,   4,  2,  0,  0,  2 },
  80.     {  4,   8,   8,  4,  0,  0,  4 },
  81.     { 12,  24,  24, 12,  0,  0, 12 },
  82.     { 22,  44,  44, 22,  0,  0, 22 },
  83.     { 44,  88,  88, 44,  0,  0, 44 },
  84.     { 87, 174, 174, 87,  0,  0, 87 }
  85. };
  86. short bsy[NUMPOWERS][7] = {
  87.     { 0 },
  88.     { 0 },
  89.     {  0,   0,   4,   4,   4,  0,  0 },
  90.     {  0,   0,   8,   8,   8,  0,  0 },
  91.     {  0,   6,  20,  26,  20,  6,  0 },
  92.     {  0,  11,  37,  48,  37, 11,  0 },
  93.     {  0,  21,  75,  96,  75, 21,  0 },
  94.     {  0,  44, 148, 192, 148, 44,  0 }
  95. };
  96.  
  97. /* Coords of middles of each hex border (half a connection, basically). */
  98.  
  99. short lsx[NUMPOWERS][6] = {
  100.     { 0 },
  101.     { 0 },
  102.     {  1,  2,   1,  -1,  -2,  -1 },
  103.     {  2,  4,   2,  -2,  -4,  -2 },
  104.     {  6, 12,   6,  -6, -12,  -6 },
  105.     { 11, 22,  11, -11, -22, -11 },
  106.     { 22, 44,  22, -22, -44, -22 },
  107.     { 44, 87,  44, -44, -87, -44 }
  108. };
  109. short lsy[NUMPOWERS][6] = {
  110.     { 0 },
  111.     { 0 },
  112.     {  -2,  0,   2,   2,   0,  -2 },
  113.     {  -4,  0,   4,   4,   0,  -4 },
  114.     {  -9,  0,   9,   9,   0,  -9 },
  115.     { -18,  0,  18,  18,   0, -18 },
  116.     { -36,  0,  36,  36,   0, -36 },
  117.     { -74,  0,  74,  74,   0, -74 }
  118. };
  119.  
  120. short qx[NUMPOWERS][7], qy[NUMPOWERS][7];
  121.  
  122. /* The traditional direction characters. */
  123.  
  124. char *dirchars = "ulnbhy";
  125.  
  126. /* The image family for regions that are not yet discovered. */
  127.  
  128. ImageFamily *unseen_image = NULL;
  129.  
  130. /* This routine finds and lists all the games that should be listed as choices for
  131.    the user. */
  132.  
  133. /* Note that we don't actually scan library folders looking for all possible game
  134.    designs therein. */
  135.  
  136. /* (should go into kernel, use an MI way of collecting games) */
  137.  
  138. Module **possible_games = NULL;
  139.  
  140. int numgames = 0;
  141.  
  142. /* The comparison function for the game list puts un-formally-named
  143.    modules at the end, plus the default sorting puts initial-lowercased
  144.    names after uppercased ones. */
  145.  
  146. static int
  147. module_name_compare(a1, a2)
  148. CONST void *a1, *a2;
  149. {
  150.     Module *mp1, *mp2;
  151.     int rslt;
  152.  
  153.     mp1 = *((Module **) a1);
  154.     mp2 = *((Module **) a2);
  155.     if (mp1->basemodulename == NULL) {
  156.     if (mp2->basemodulename == NULL) {
  157.         /* Modules must always have a non-NULL name. */
  158.         return strcmp(mp1->name, mp2->name);
  159.     } else {
  160.         rslt = strcmp(mp1->name, mp2->basemodulename);
  161.         if (rslt == 0) rslt = -1;
  162.         return rslt;
  163.     }
  164.     } else {
  165.     if (mp2->basemodulename == NULL) {
  166.         rslt = strcmp(mp1->basemodulename, mp2->name);
  167.         if (rslt == 0) rslt = 1;
  168.         return rslt;
  169.     } else {
  170.         rslt = strcmp(mp1->basemodulename, mp2->basemodulename);
  171.         if (rslt != 0)
  172.           return rslt;
  173.         if (mp1->title == NULL) {
  174.         if (mp2->title == NULL) {
  175.             /* Modules must always have a non-NULL name. */
  176.             return strcmp(mp1->name, mp2->name);
  177.         } else {
  178.             return 1;
  179.         }
  180.         } else {
  181.         if (mp2->title == NULL) {
  182.             return (-1);
  183.         } else {
  184.             return strcmp(mp1->title, mp2->title);
  185.         }
  186.         }
  187.     }
  188.     }
  189. }
  190.  
  191. static int max_possible_games;
  192.  
  193. void
  194. collect_possible_games()
  195. {
  196.     int numresources = 0, len, i;
  197.     char *modulename = NULL, *modulecontents = NULL;
  198.     Obj *lis;
  199.     Module *module, *basemodule;
  200.     FILE *fp;
  201.     int startline = 0, endline = 0;
  202.  
  203.     if (numgames == 0 && numutypes == 0 /* !game_already_loaded() */) {
  204.     len = 0;
  205.     fp = open_library_file("game.dir");
  206.     if (fp != NULL) {
  207.         lis = read_form(fp, &startline, &endline);
  208.         if (consp(lis))
  209.           len = length(lis);
  210.         fclose(fp);
  211.     }
  212. #ifdef MAC
  213.     numresources = CountResources('XCgm');
  214. #endif /* MAC */
  215.     max_possible_games = 2 + (len + numresources) * 2;
  216.     /* Make enough room to record all the possible games. */
  217.     possible_games = (Module **) xmalloc(max_possible_games * sizeof(Module *));
  218.     /* Collect the intro and standard game modules and put at head
  219.        of list. */
  220.     module = get_game_module(first_game_name);
  221.     add_to_possible_games(module);
  222.     module = get_game_module(second_game_name);
  223.     add_to_possible_games(module);
  224.     /* Pick up game modules that are specified as resources. */
  225.     for (; lis != lispnil; lis = cdr(lis)) {
  226.         if (!(symbolp(car(lis)) || stringp(car(lis)))) {
  227.         /* (should warn about garbage in list) */
  228.         continue;
  229.         }
  230.         modulename = c_string(car(lis));
  231.         if (modulename != NULL) {
  232.         module = get_game_module(modulename);
  233.         module->contents = modulecontents;
  234.         add_to_possible_games(module);
  235.         if (module->basemodulename != NULL) {
  236.             basemodule = get_game_module(module->basemodulename);
  237.             add_to_possible_games(basemodule);
  238.         }
  239.         }
  240.     }
  241. #ifdef MAC
  242.     /* Pick up game modules that are specified as resources. */
  243.     for (i = 0; i < numresources; ++i) {
  244.         Handle modulehandle;
  245.         short moduleid;
  246.         ResType restype;
  247.         Str255 resname;
  248.  
  249.         modulehandle = GetIndResource('XCgm', i + 1);
  250.         /* (should test for resource validity?) */
  251.         if (0 /* size > 0 */) {
  252.         /* set modulecontents from resource */
  253.         modulecontents = NULL;
  254.         }
  255.         /* Try to pick up module name from its resource name, otherwise
  256.            assume its name in its content. */
  257.         GetResInfo(modulehandle, &moduleid, &restype, resname);
  258.         if (resname[0] > 0) {
  259.         resname[resname[0]+1] = '\0';
  260.         modulename = copy_string((char *) resname+1);
  261.         } else {
  262.         modulename = NULL;
  263.         }
  264.         if (modulename != NULL) {
  265.         module = get_game_module(modulename);
  266.         module->contents = modulecontents;
  267.         add_to_possible_games(module);
  268.         if (module->basemodulename != NULL) {
  269.             basemodule = get_game_module(module->basemodulename);
  270.             add_to_possible_games(basemodule);
  271.         }
  272.         }
  273.     }
  274. #endif /* MAC */
  275.     if (numgames > 3) {
  276.         /* Sort all but the first two games into alphabetical order
  277.            by displayed name. */
  278.         qsort(&(possible_games[2]), numgames - 2, sizeof(Module *),
  279.           module_name_compare);
  280.     }
  281.     }
  282. }
  283.  
  284. /* Load a game's description and add it to the list of games. */
  285.  
  286. void
  287. add_to_possible_games(module)
  288. Module *module;
  289. {
  290.     int i;
  291.  
  292.     if (module != NULL) {
  293.     if (load_game_description(module)) {
  294.         /* It might be that the module description supplies the real name,
  295.            and that the module already exists. (work on this) */
  296.         /* Don't add duplicate modules. */
  297.         for (i = 0; i < numgames; ++i) {
  298.         if (possible_games[i] == module)
  299.           return;
  300.         }
  301.         if (numgames < max_possible_games) {
  302.         possible_games[numgames++] = module;
  303.         }
  304.     }
  305.     }
  306. }
  307.  
  308. /* Choose and return a reasonable location for map displays to start out
  309.    centered on. */
  310.  
  311. void
  312. pick_a_focus(side, xp, yp)
  313. Side *side;
  314. int *xp, *yp;
  315. {
  316.     int num = 0, sumx = 0, sumy = 0, tmpx, tmpy, dist, closest = area.maxdim;
  317.     Unit *unit, *closestunit = NULL;
  318.  
  319.     if (side->startx < 0 || side->starty < 0)
  320.       calc_start_xy(side);
  321.     if (side->startx < 0 || side->starty < 0) {
  322.     *xp = area.width / 2 - area.height / 4;  *yp = area.height / 2;
  323.     } else {
  324.     tmpx = side->startx;  tmpy = side->starty;
  325.     /* Rescan the units to find a closest one. */
  326.     for_all_side_units(side, unit) {
  327.         if (in_play(unit)) {
  328.         /* If already got one right there, just return. */
  329.         if (unit->x == tmpx && unit->y == tmpy) {
  330.             *xp = tmpx;  *yp = tmpy;
  331.             return;
  332.         } else {
  333.             dist = distance(unit->x, unit->y, tmpx, tmpy);
  334.             if (dist < closest) {
  335.             closest = dist;
  336.             closestunit = unit;
  337.             }
  338.         }
  339.         }
  340.     }
  341.     if (closestunit != NULL) {
  342.         /* Return the position of the unit closest to the avg position. */
  343.         *xp = closestunit->x;  *yp = closestunit->y;
  344.     } else {
  345.         *xp = tmpx;  *yp = tmpy;
  346.     }
  347.     }
  348. }
  349.  
  350. int
  351. num_active_displays()
  352. {
  353.     int n = 0;
  354.     Side *side;
  355.  
  356.     for_all_sides(side) {
  357.     if (active_display(side))
  358.       ++n;
  359.     }
  360.     return n;
  361. }
  362.  
  363. int cellwidthguess = -1;
  364. int avgelev;
  365. int vertexagg = 1;
  366.  
  367. void
  368. guess_elev_stuff()
  369. {
  370.     int x, y, el;
  371.     long count = 0, sum = 0, maxelev = -9999;
  372.  
  373.     for_all_cells(x, y) {
  374.     ++count;
  375.     el = elev_at(x, y);
  376.     sum += el;
  377.     if (el > maxelev) maxelev = el;
  378.     }
  379.     avgelev = sum / count;
  380.     cellwidthguess = (area.cellwidth > 1 ? area.cellwidth : max(2, (maxelev - avgelev) * 2));
  381. }
  382.  
  383. static q_computed = FALSE;
  384.  
  385. void compute_q PROTO ((void));
  386.  
  387. void compute_q()
  388. {
  389.     int d, p, w;
  390.  
  391.     if (q_computed)
  392.       return;
  393.     for (p = 0; p < NUMPOWERS; ++p) {
  394.         if (p < 2)
  395.           continue;
  396.         w = bwid[p] + 1;
  397.         for_all_directions(d) {
  398.         qx[p][d] = bsx[p][d] + ((hws[p] - 2 * bsx[p][d]) * w) / (2 * mags[p]);
  399.         qy[p][d] = bsy[p][d] + ((hhs[p] - 2 * bsy[p][d]) * w) / (2 * mags[p]);
  400.         }
  401.         qx[p][NUMDIRS] = qx[p][0];
  402.         qy[p][NUMDIRS] = qy[p][0];
  403.     }
  404.     q_computed = TRUE;
  405. }
  406.  
  407. VP *
  408. new_vp()
  409. {
  410.     VP *vp;
  411.  
  412.     compute_q();  /* a hack */
  413.     vp = (VP *) xmalloc(sizeof(VP));
  414.     /* View at a 90 degree angle by default. */
  415.     vp->angle = 90;
  416.     return vp;
  417. }
  418.  
  419. /* Given a viewport and a cell, figure out where it UL corner will be. */
  420.  
  421. void
  422. xform_cell(vp, x, y, sxp, syp)
  423. VP *vp;
  424. int x, y, *sxp, *syp;
  425. {
  426.     extern int cellwidthguess, avgelev, vertexagg;
  427.  
  428.     if (in_area(x, y)) {
  429.     *sxp = x * vp->hw + (y * vp->hw) / 2 - vp->sx;
  430. #if 0 /* if two possibilities for sx, let caller make the choice and do the work */
  431.     if (area.xwrap && *sxp < (- vp->hw))
  432.       *sxp += area.width * vp->hw;
  433. #endif
  434.     *syp = (vp->totsh - (vp->hh + y * vp->hch)) - vp->sy;
  435.     if (vp->angle != 90 && elevations_defined()) {
  436.         int elev, offset;
  437.         if (cellwidthguess < 0) {
  438.         guess_elev_stuff();
  439.         }
  440.         elev = elev_at(x, y) - avgelev + t_thickness(terrain_at(x, y));
  441.         elev *= vertexagg;
  442.         offset = (elev * vp->hh) / cellwidthguess;
  443.         *syp -= offset;
  444.     }
  445.     } else {
  446.     /* Always die on this, indicates bugs that must be fixed. */
  447.     run_error("attempting to xform %d,%d", x, y);
  448.     }
  449. }
  450.  
  451. void
  452. xform_unit(vp, unit, sxp, syp, swp, shp)
  453. VP *vp;
  454. Unit *unit;
  455. int *sxp, *syp, *swp, *shp;
  456. {
  457.     int num = 0, n = -1, sq, sx, sy, sx1, sy1, sw1, sh1;
  458.     int x = unit->x, y = unit->y;
  459.     Unit *unit2;
  460.  
  461.     if (unit->transport == NULL) {
  462.     xform_cell(vp, x, y, &sx, &sy);
  463.     /* Adjust to the unit box within the cell. */
  464.     sx += (vp->hw - vp->uw) / 2;  sy += (vp->hh - vp->uh) / 2;
  465.     /* Figure out our position in this cell's stack. */
  466.     for_all_stack(x, y, unit2) {
  467.         if (unit == unit2) n = num;
  468.         ++num;
  469.     }
  470.     if (n < 0) run_error("xform_unit weirdness");
  471.     if (num <= 1) {
  472.         sq = 1;
  473.     } else if (num <= 4) {
  474.         sq = 2;
  475.     } else if (num <= 16) {
  476.         sq = 4;
  477.     } else if (num <= 256) {
  478.         sq = 8;
  479.     } else {
  480.         /* This is room for 65,536 units in a stack. */
  481.         sq = 16;
  482.     }
  483.     *swp = vp->uw / sq;  *shp = vp->uh / sq;
  484.     *sxp = sx + *swp * (n / sq);  *syp = sy + *shp * (n % sq);
  485.     } else {
  486.     /* Go up the transport chain to get the bounds for this unit. */
  487.     xform_unit(vp, unit->transport, &sx1, &sy1, &sw1, &sh1);
  488.     xform_occupant(vp, unit->transport, unit, sx1, sy1, sw1, sh1, sxp, syp, swp, shp);
  489.     }
  490. }
  491.  
  492. void
  493. xform_unit_self(vp, unit, sxp, syp, swp, shp)
  494. VP *vp;
  495. Unit *unit;
  496. int *sxp, *syp, *swp, *shp;
  497. {
  498.     int sx1, sy1, sw1, sh1;
  499.  
  500.     if (unit->transport == NULL) {
  501.     if (unit->occupant == NULL) {
  502.         xform_unit(vp, unit, sxp, syp, swp, shp);
  503.     } else {
  504.         xform_unit(vp, unit, &sx1, &sy1, &sw1, &sh1);
  505.         xform_occupant(vp, unit, unit, sx1, sy1, sw1, sh1, sxp, syp, swp, shp);
  506.     }
  507.     } else {
  508.     xform_unit(vp, unit->transport, &sx1, &sy1, &sw1, &sh1);
  509.     xform_occupant(vp, unit->transport, unit, sx1, sy1, sw1, sh1, sxp, syp, swp, shp);
  510.     }
  511. }
  512.  
  513. void
  514. xform_occupant(vp, transport, unit, sx, sy, sw, sh, sxp, syp, swp, shp)
  515. VP *vp;
  516. Unit *transport, *unit;
  517. int sx, sy, sw, sh, *sxp, *syp, *swp, *shp;
  518. {
  519.     int num = 0, n = -1, nmx, nmy;
  520.     Unit *unit2;
  521.  
  522.     /* Figure out the position of this unit amongst all the occupants. */
  523.     for_all_occupants(transport, unit2) {
  524.     if (unit2 == unit) n = num;
  525.     ++num;
  526.     }
  527.     if (unit == transport) {
  528.     if (num > 0) {
  529.         /* Transport image shrinks by half in each dimension. */
  530.         *swp = sw / 2;  *shp = sh / 2;
  531.     }
  532.     /* Transport is always in the UL corner. */
  533.     *sxp = sx;  *syp = sy;
  534.     } else {
  535.     if (n < 0) run_error("xform_occupant weirdness");
  536.     /* Compute how the half-box will be subdivided.  Only use powers of two,
  537.        so image scaling works better. */
  538.     if (num <= 2) {
  539.         nmx = 2;
  540.     } else if (num <= 8) {
  541.         nmx = 4;
  542.     } else if (num <= 128) {
  543.         nmx = 8;
  544.     } else {
  545.         /* This is room for 32,768 units in a stack. */
  546.         nmy = 16;
  547.     }
  548.     nmy = nmx / 2;
  549.     *swp = sw / nmx;  *shp = (sh / 2) / nmy;
  550.     *sxp = sx + *swp * (n / nmy);  *syp = sy + sh / 2 + *shp * (n % nmy);
  551.     }
  552. }
  553.  
  554. /* Scale one viewport box to its position in another. */
  555.  
  556. void
  557. scale_vp(vp, vp2, sxp, syp, swp, shp)
  558. VP *vp, *vp2;
  559. int *sxp, *syp, *swp, *shp;
  560. {
  561.     *sxp = (vp2->sx * vp->hw) / vp2->hw - vp->sx;
  562.     *syp = (vp2->sy * vp->hch) / vp2->hch - vp->sy;
  563.     *swp = (vp2->pxw * vp->hw) / vp2->hw;
  564.     *shp = (vp2->pxh * vp->hch) / vp2->hch;
  565. }
  566.  
  567. int
  568. nearest_cell(vp, sx, sy, xp, yp)
  569. VP *vp;
  570. int sx, sy, *xp, *yp;
  571. {
  572.     /* Flip the raw y and then scale to hex coords. */
  573.     *yp = (vp->totsh - (vp->sy + sy)) / vp->hch;
  574.     /* Scale adjusted x to hex coord. */
  575.     *xp = (sx + vp->sx - (*yp * vp->hw) / 2) / vp->hw;
  576.     /* If the magnification of the map is large enough that the top and bottom
  577.        edges of a hex are visibly sloping, then we have to take those edges
  578.        int account, and accurately. */
  579.     if ((vp->hh - vp->hch) / 2 > 1) {
  580.     /* (should adjust according to hex boundaries correctly here) */
  581.     }
  582.     /* Wrap coords as usual. */
  583.     if (area.xwrap)
  584.       *xp = wrapx(*xp);
  585.     DGprintf("Pixel %d,%d -> hex %d,%d\n", sx, sy, *xp, *yp);
  586.     return (in_area(*xp, *yp));
  587. }
  588.  
  589. int
  590. nearest_boundary(vp, sx, sy, xp, yp, dirp)
  591. VP *vp;
  592. int sx, sy, *xp, *yp, *dirp;
  593. {
  594.     int sx2, sy2, ydelta, hexslope;
  595.  
  596.     /* Get the nearest cell... */
  597.     if (nearest_cell(vp, sx, sy, xp, yp)) {
  598.     /* ... and xform it back to get the pixel coords. */ 
  599.     xform_cell(vp, *xp, *yp, &sx2, &sy2);
  600.     ydelta = sy - sy2;
  601.     hexslope = (vp->hh - vp->hch) / 2;
  602.     if (sx - sx2 > vp->hw / 2) {
  603.         *dirp = ((ydelta < hexslope) ? NORTHEAST : (ydelta > vp->hch ? SOUTHEAST : EAST));
  604.     } else {
  605.         *dirp = ((ydelta < hexslope) ? NORTHWEST : (ydelta > vp->hch ? SOUTHWEST : WEST));
  606.     }
  607.     DGprintf("Pixel %d,%d -> hex %d,%d dir %d\n", sx, sy, *xp, *yp, *dirp);
  608.     return TRUE;
  609.     } else {
  610.     return FALSE;
  611.     }
  612. }
  613.  
  614. Unit *
  615. find_unit_or_occ(vp, unit, usx, usy, usw, ush, sx, sy)
  616. VP *vp;
  617. Unit *unit;
  618. int usx, usy, usw, ush, sx, sy;
  619. {
  620.     int usx1, usy1, usw1, ush1;
  621.     Unit *occ, *rslt;
  622.  
  623.     /* See if the point might be over an occupant. */
  624.     if (unit->occupant != NULL) {
  625.     for_all_occupants(unit, occ) {
  626.         xform_unit(vp, occ, &usx1, &usy1, &usw1, &ush1);
  627.         rslt = find_unit_or_occ(vp, occ, usx1, usy1, usw1, ush1, sx, sy);
  628.         if (rslt)
  629.           return rslt;
  630.     }
  631.     }
  632.     /* Otherwise see if it could be the unit itself.  This has the effect of
  633.        "giving" the transport everything in its box that is not in an occ. */
  634.     xform_unit(vp, unit, &usx1, &usy1, &usw1, &ush1);
  635.     if (between(usx1, sx, usx1 + usw1) && between(usy1, sy, usy1 + ush1))
  636.       return unit;
  637.     return NULL;
  638. }
  639.  
  640. Unit *
  641. find_unit_at(vp, x, y, sx, sy)
  642. VP *vp;
  643. int x, y, sx, sy;
  644. {
  645.     int usx, usy, usw, ush;
  646.     Unit *unit, *rslt;
  647.     
  648.     for_all_stack(x, y, unit) {
  649.     xform_unit(vp, unit, &usx, &usy, &usw, &ush);
  650.     rslt = find_unit_or_occ(vp, unit, usx, usy, usw, ush, sx, sy);
  651.     if (rslt)
  652.       return rslt;
  653.     }
  654.     return NULL;
  655. }
  656.  
  657. int
  658. nearest_unit(vp, sx, sy, unitp)
  659. VP *vp;
  660. int sx, sy;
  661. Unit **unitp;
  662. {
  663.     int x, y;
  664.     
  665.     if (!nearest_cell(vp, sx, sy, &x, &y)) {
  666.     *unitp = NULL;
  667.     } else if (vp->power > 4) {
  668.     *unitp = find_unit_at(vp, x, y, sx, sy);
  669.     } else {
  670.     *unitp = unit_at(x, y);
  671.     }
  672.     DGprintf("Pixel %d,%d -> unit %s\n", sx, sy, unit_desig(*unitp));
  673.     return 0;
  674. }
  675.  
  676. int
  677. cell_is_visible(vp, x, y)
  678. VP *vp;
  679. int x, y;
  680. {
  681.     int sx, sy;
  682.  
  683.      if (!in_area(x, y))
  684.        return FALSE;   
  685.     xform_cell(vp, x, y, &sx, &sy);
  686.     if (area.xwrap && sx > vp->totsw)
  687.       sx -= vp->totsw;
  688.     if (sx + vp->hw < 0)
  689.       return FALSE;
  690.     if (sx > vp->pxw) 
  691.       return FALSE;
  692.     if (sy + vp->hh < 0)
  693.       return FALSE;
  694.     if (sy > vp->pxh)
  695.       return FALSE;
  696.     return TRUE;
  697. }
  698.  
  699. /* Decide whether given location is away from the edge of the map's window. */
  700.  
  701. int
  702. cell_is_in_middle(vp, x, y)
  703. VP *vp;
  704. int x, y;
  705. {
  706.     int sx, sy, insetx1, insety1, insetx2, insety2;
  707.     
  708.      if (!in_area(x, y))
  709.        return FALSE;   
  710.     xform_cell(vp, x, y, &sx, &sy);
  711.     /* Adjust to be the center of the cell, more reasonable if large. */
  712.     sx += vp->hw / 2;  sy += vp->hh / 2;
  713.     insetx1 = min(vp->pxw / 4, 1 * vp->hw);
  714.     insety1 = min(vp->pxh / 4, 1 * vp->hch);
  715.     insetx2 = min(vp->pxw / 4, 2 * vp->hw);
  716.     insety2 = min(vp->pxh / 4, 2 * vp->hch);
  717.     if (sx < insetx2)
  718.       return FALSE;
  719.     if (sx > vp->pxw - insetx2)
  720.       return FALSE;
  721.     if (sy < (between(2, y, area.height-3) ? insety2 : insety1))
  722.       return FALSE;
  723.     if (sy > vp->pxh - (between(2, y, area.height-3) ? insety2 : insety1))
  724.       return FALSE;
  725.     return TRUE;
  726. }
  727.  
  728. /* Set vcx/vcy to point to the center of the view. */
  729.  
  730. void
  731. focus_on_center(vp)
  732. VP *vp;
  733. {
  734.     vp->vcy = (vp->totsh - (vp->sy + vp->pxh / 2)) / vp->hch;
  735.     vp->vcx = vp->sx / vp->hw - (vp->vcy / 2) + (vp->pxw / vp->hch) / 2;
  736.     /* Restrict the focus to be *inside* the area. */
  737.     vp->vcy = max(1, min(vp->vcy, area.height - 2));
  738.     if (area.xwrap) {
  739.     vp->vcx = wrapx(vp->vcx);
  740.     } else {
  741.     vp->vcx = max(1, min(vp->vcx, area.width - 2));
  742.     if (vp->vcx + vp->vcy < area.height / 2 + 1)
  743.       vp->vcx = area.height / 2 + 1;
  744.     if (vp->vcx + vp->vcy > area.width + area.height / 2 - 1)
  745.       vp->vcx = area.width + area.height / 2 - 1;
  746.     }
  747. }
  748.  
  749. void
  750. center_on_focus(vp)
  751. VP *vp;
  752. {
  753.     /* Scale, add hex offset adjustment, translate to get left edge. */
  754.     vp->sx = vp->vcx * vp->hw + (vp->vcy * vp->hw) / 2 - vp->pxw / 2 + vp->hw / 2;
  755.     /* Scale, translate to top edge, flip. */
  756.     vp->sy = vp->totsh - (vp->vcy * vp->hch + vp->pxh / 2 + vp->hh / 2);
  757.     /* Weird vcx,vcy might make sx,sy nonsensical, so clip to rational
  758.        limits. */
  759.     vp->sx = max(hexagon_adjust(vp), min(vp->sx, vp->totsw - vp->pxw));
  760.     vp->sy = max(0, min(vp->sy, vp->totsh - vp->pxh));
  761.     DGprintf("View at %d,%d, focused at %d,%d\n",
  762.          vp->sx, vp->sy, vp->vcx, vp->vcy);
  763. }
  764.  
  765. int
  766. set_view_size(vp, w, h)
  767. VP *vp;
  768. int w, h;
  769. {
  770.     /* (should limit these values) */
  771.     vp->pxw = w;  vp->pxh = h;
  772.     return TRUE;
  773. }
  774.  
  775. int
  776. set_view_position(vp, sx, sy)
  777. VP *vp;
  778. int sx, sy;
  779. {
  780.     /* (should limit these values) */
  781.     vp->sx = sx;  vp->sy = sy;
  782.     /* Clip to rational limits. */
  783.     vp->sx = max(hexagon_adjust(vp), min(vp->sx, vp->totsw - vp->pxw));
  784.     vp->sy = max(0, min(vp->sy, vp->totsh - vp->pxh));
  785.     return TRUE;
  786. }
  787.  
  788. /* Given a magnification power, calculate and cache the sizes within a cell,
  789.    and the scaled size in pixels of the entire world. */
  790.  
  791. int
  792. set_view_power(vp, power)
  793. VP *vp;
  794. int power;
  795. {
  796.     vp->power = power;
  797.     vp->mag = mags[power]; /* is this used?? */
  798.     vp->hw = hws[power];  vp->hh = hhs[power];
  799.     vp->hch = hcs[power];
  800.     vp->uw = uws[power];  vp->uh = uhs[power];
  801.     if (vp->angle == 30) {
  802.     vp->hh /= 2;
  803.     vp->hch /= 2;
  804.     } else if (vp->angle == 15) {
  805.     vp->hh /= 4;
  806.     vp->hch /= 4;
  807.     }
  808.     /* Calculate and cache the width in pixels of the whole area, adding an
  809.        an adjustment to account for the "bulge" of hexagon-shaped areas. */
  810.     vp->totsw = area.width * vp->hw + hexagon_adjust(vp);
  811.     /* Total scaled height is based on center-to-center height, plus an adjustment
  812.        to include the bottom parts of the bottom row. */
  813.     vp->totsh = area.height * vp->hch + (vp->hh - vp->hch);
  814.     DGprintf("Power is now %d, total scaled area is %d x %d\n",
  815.          vp->power, vp->totsw, vp->totsh);
  816.     return TRUE;
  817. }
  818.  
  819. int
  820. set_view_focus(vp, x, y)
  821. VP *vp;
  822. int x, y;
  823. {
  824.     vp->vcx = x;  vp->vcy = y;
  825.     return TRUE;
  826. }
  827.  
  828. int
  829. set_view_angle(vp, angle)
  830. VP *vp;
  831. int angle;
  832. {
  833.     if (!(angle == 90 || angle == 30 || angle == 15)) {
  834.     run_warning("Bad angle %d, setting to 90", angle);
  835.     angle = 90;
  836.     }
  837.     vp->angle = angle;
  838.     vp->hh = hhs[vp->power];
  839.     vp->hch = hcs[vp->power];
  840.     vp->uh = uhs[vp->power];
  841.     if (vp->angle == 30) {
  842.     vp->hh /= 2;
  843.     vp->hch /= 2;
  844.     vp->uh /= 2;
  845.     } else if (vp->angle == 15) {
  846.     vp->hh /= 4;
  847.     vp->hch /= 4;
  848.     vp->uh /= 4;
  849.     }
  850.     /* Total scaled height is based on center-to-center height, plus an
  851.        adjustment to include the bottom parts of the bottom row. */
  852.     vp->totsh = area.height * vp->hch + (vp->hh - vp->hch);
  853.     DGprintf("Angle is now %d, total scaled area is %d x %d\n",
  854.          vp->angle, vp->totsw, vp->totsh);
  855.     return TRUE;
  856. }
  857.  
  858. int
  859. set_view_direction(vp, dir)
  860. VP *vp;
  861. int dir;
  862. {
  863.     return TRUE;
  864. }
  865.  
  866.  
  867. /* (needs a better home?) */
  868.  
  869. /* Given a side and a unit, calculate the correct "next unit".  Typically
  870.    used by autonext options, thus the name. */
  871.  
  872. Unit *
  873. autonext_unit(side, unit)
  874. Side *side;
  875. Unit *unit;
  876. {
  877.     int i, uniti = -1, n;
  878.     Unit *nextunit;
  879.  
  880.     if (!side->ingame
  881.     || side->finishedturn
  882.     || actionvector == NULL)
  883.       return NULL;
  884.     if (could_be_next_unit(unit) && side_controls_unit(side, unit))
  885.       return unit;
  886.     for (i = 0; i < actionvector->numunits; ++i) {
  887.         nextunit = (actionvector->units)[i].unit;
  888.         if (in_play(nextunit) && side_controls_unit(side, nextunit)) {
  889.         if (unit == NULL || unit == nextunit) {
  890.         uniti = i;
  891.         break;
  892.         }
  893.         }
  894.     }
  895.     if (uniti < 0)
  896.       return NULL;
  897.     /* (should scan for both a preferred and an alternate - preferred
  898.        could be within a supplied bbox so as to avoid scrolling) */
  899.     for (i = uniti; i < uniti + actionvector->numunits; ++i) {
  900.         n = i % actionvector->numunits;
  901.         nextunit = (actionvector->units)[n].unit;
  902.         if (could_be_next_unit(nextunit) && side_controls_unit(side, nextunit))
  903.           return nextunit;
  904.     }
  905.     return NULL;
  906. }
  907.  
  908. #if 0
  909. int
  910. in_box(x, y, lx, ly, w, h)
  911. int x, y, lx, ly, w, h;
  912. {
  913.     if ( !between(ly, y, ly+h) )
  914.       return FALSE;
  915.     lx -= (y - ly) / 2;
  916.     return between(lx, x, lx+w);
  917. }
  918. #endif
  919.  
  920. /*
  921.  * This should really be called autonext_unit and the decision
  922.  * whether to check inbox or not should depend on the bbox being
  923.  * valid. i.e. could be called with -1,-1,-1,-1 to disable the bbox.
  924.  */
  925. Unit *
  926. autonext_unit_inbox(side, unit, vp)
  927. Side *side;
  928. Unit *unit;
  929. VP *vp;
  930. {
  931.     int i, u, mx, my, val, prefval = -999, v = 10;
  932.     Unit *nextunit = NULL, *prefunit = NULL;
  933.  
  934.     if (!side->ingame || side->finishedturn || actionvector == NULL)
  935.       return NULL;
  936.  
  937.     /* degenerate case... this unit still has stuff to do. */
  938.     if (could_be_next_unit(unit) && side_controls_unit(side, unit))
  939.     return unit;
  940.  
  941.     if (unit == NULL) {
  942.     u = 0;
  943.     if (!nearest_cell(vp, vp->sx + vp->pxw / 2, vp->sy + vp->pxh / 2, &mx, &my)) {
  944.         mx = area.width / 2;  my = area.height / 2;
  945.     }
  946.     } else {
  947.     u = unit->type;
  948.     mx = unit->x;  my = unit->y;
  949.     }
  950.  
  951.     for (i = 0; i < actionvector->numunits; ++i) {
  952.         nextunit = (actionvector->units)[i].unit;
  953.     if (side_controls_unit(side, nextunit) && could_be_next_unit(nextunit)) {
  954.         val = v - distance(nextunit->x, nextunit->y, mx, my);
  955.         if (cell_is_in_middle(vp, nextunit->x, nextunit->y))
  956.           val += v;
  957.         if (nextunit->type == u)
  958.           val += 2;
  959.  
  960.         if (val > prefval) {
  961.         prefval = val;
  962.         prefunit = nextunit;
  963.         }
  964.     }
  965.     }
  966.     return prefunit;
  967. }
  968.  
  969. int
  970. could_be_next_unit(unit)
  971. Unit *unit;
  972. {
  973.     return (unit != NULL
  974.         && alive(unit)
  975.         && inside_area(unit->x, unit->y)
  976.         && (unit->act
  977.         && unit->act->acp > 0 /*
  978.         && !has_pending_action(unit) */)
  979.         && (unit->plan
  980.         && !unit->plan->asleep
  981.         && !unit->plan->reserve
  982.         && !unit->plan->delayed
  983.         && unit->plan->waitingfortasks));
  984. }
  985.  
  986. /* Given that the player desires to move the given unit into the given
  987.    cell/other unit, prepare a "most appropriate" action. */
  988.    /* (should share diff cell and same cell interaction code) */
  989. /* (should reindent) */
  990. int
  991. advance_into_cell(side, unit, x, y, other)
  992. Side *side;
  993. Unit *unit, *other;
  994. int x, y;
  995. {
  996. #ifdef DESIGNERS
  997.     /* Designers use this function to push units around, bound only by the
  998.        limits on occupancy. */
  999.     if (side->designer) {
  1000.     if (other != NULL && can_occupy(unit, other)) {
  1001.         /* Teleport into a transport. */
  1002.         leave_cell(unit);
  1003.         enter_transport(unit, other);
  1004.     } else if (can_occupy_cell(unit, x, y)) {
  1005.         designer_teleport(unit, x, y);
  1006.     } else {
  1007.         return FALSE;
  1008.     }
  1009.     return TRUE;
  1010.     }
  1011. #endif /* DESIGNERS */
  1012.     if (x != unit->x || y != unit->y) {
  1013.     if (unit->act && unit->plan) { /* (should be more sophisticated test?) */
  1014.         if (distance(unit->x, unit->y, x, y) == 1) {
  1015.         if (other == NULL) {
  1016.             if (can_occupy_cell(unit, x, y)
  1017.             && valid(check_move_action(unit, unit, x, y, unit->z))) {
  1018.             prep_move_action(unit, unit, x, y, unit->z);
  1019.             return TRUE;
  1020.             } else {
  1021.             return FALSE;
  1022.             }
  1023.         }
  1024.         if (unit_trusts_unit(unit, other)) {
  1025.             /* A friend, maybe get on it. */
  1026.             if (can_occupy(unit, other)) {
  1027.             if (valid(check_enter_action(unit, unit, other))) {
  1028.                 prep_enter_action(unit, unit, other);
  1029.             } else {
  1030.                 /* (should schedule for next turn?) */
  1031.             }
  1032.             } else if (can_occupy(other, unit)) {
  1033.             if (u_acp(other->type) > 0) {
  1034.                 /* Have other unit do an enter action,
  1035.                                then move. */
  1036.                 /* (not quite right, move should happen
  1037.                    after other unit is actually inside, in
  1038.                    case it fills dest) */
  1039.                 prep_enter_action(other, other, unit);
  1040.                 order_moveto(unit, x, y);
  1041.             } else {
  1042.                 prep_enter_action(unit, other, unit);
  1043.                 order_moveto(unit, x, y);
  1044.             }
  1045.             } else if (other->transport != NULL
  1046.                    && can_occupy(unit, other->transport)) {
  1047.             if (valid(check_enter_action(unit, unit, other->transport))) {
  1048.                 prep_enter_action(unit, unit, other->transport);
  1049.             } else {
  1050.                 /* (should schedule for next turn?) */
  1051.             }
  1052.             } else if (other->transport != NULL
  1053.                    && other->transport->transport != NULL
  1054.                    && can_occupy(unit, other->transport->transport)) {
  1055.             /* two levels up should be sufficient */
  1056.             if (valid(check_enter_action(unit, unit, other->transport->transport))) {
  1057.                 prep_enter_action(unit, unit, other->transport->transport);
  1058.             } else {
  1059.                 /* (should schedule for next turn?) */
  1060.             }
  1061.             } else if (valid(check_transfer_part_action(unit, unit, unit->hp, other))) {
  1062.             prep_transfer_part_action(unit, unit, unit->hp, other);
  1063.             } else if (can_occupy_cell(unit, x, y)
  1064.                    && valid(check_move_action(unit, unit, x, y, unit->z))) {
  1065.             prep_move_action(unit, unit, x, y, unit->z);
  1066.             } else {
  1067.             return FALSE;
  1068.             }
  1069.         } else {
  1070.             /* Somebody else's unit, try to victimize it in various ways,
  1071.                trying coexistence only as a last resort. */
  1072.             if (valid(check_capture_action(unit, unit, other))) {
  1073.             prep_capture_action(unit, unit, other);
  1074.             } else if (valid(check_overrun_action(unit, unit, x, y, unit->z, 100))) {
  1075.             prep_overrun_action(unit, unit, x, y, unit->z, 100);
  1076.             } else if (valid(check_attack_action(unit, unit, other, 100))) {
  1077.             prep_attack_action(unit, unit, other, 100);
  1078.             } else if (valid(check_fire_at_action(unit, unit, other, -1))) {
  1079.             prep_fire_at_action(unit, unit, other, -1);
  1080.             } else if (valid(check_detonate_action(unit, unit, x, y, unit->z))) {
  1081.             prep_detonate_action(unit, unit, x, y, unit->z);
  1082.             } else if (valid(check_move_action(unit, unit, x, y, unit->z))) {
  1083.             prep_move_action(unit, unit, x, y, unit->z);
  1084.             } else {
  1085.             return FALSE;
  1086.             }
  1087.         }
  1088.         } else {
  1089.         /* We're not adjacent to the destination, set up a move task. */
  1090.         order_moveto(unit, x, y);
  1091.         }
  1092.     } else {
  1093.         /* ??? can't act ??? */
  1094.     }
  1095.     } else {
  1096.     /* Destination is in the unit's own cell. */
  1097.     if (other != NULL) {
  1098.         if (unit_trusts_unit(unit, other)) {
  1099.             if (valid(check_transfer_part_action(unit, unit, unit->hp, other))) {
  1100.             prep_transfer_part_action(unit, unit, unit->hp, other);
  1101.             } else if (valid(check_enter_action(unit, unit, other))) {
  1102.             prep_enter_action(unit, unit, other);
  1103.             } else {
  1104.             return FALSE;
  1105.             }
  1106.         } else {
  1107.             /* Somebody else's unit, try to victimize it in various ways,
  1108.                trying coexistence only as a last resort. */
  1109.             if (valid(check_capture_action(unit, unit, other))) {
  1110.             prep_capture_action(unit, unit, other);
  1111.             } else if (valid(check_attack_action(unit, unit, other, 100))) {
  1112.             prep_attack_action(unit, unit, other, 100);
  1113.             } else if (valid(check_fire_at_action(unit, unit, other, -1))) {
  1114.             prep_fire_at_action(unit, unit, other, -1);
  1115.             } else if (valid(check_detonate_action(unit, unit, x, y, unit->z))) {
  1116.             prep_detonate_action(unit, unit, x, y, unit->z);
  1117.             } else {
  1118.             return FALSE;
  1119.             }
  1120.         }
  1121.     } else if (unit->transport != NULL) {
  1122.         /* Unit is an occupant wanting to leave, but yet remain in
  1123.            the same cell as the transport. */
  1124.         if (valid(check_move_action(unit, unit, x, y, unit->z))) {
  1125.         prep_move_action(unit, unit, x, y, unit->z);
  1126.         } else {
  1127.         return FALSE;
  1128.         }
  1129.     } else {
  1130.         /* This is a no-op, don't do anything. */
  1131.     }
  1132.     }
  1133.     return TRUE;
  1134. }
  1135.  
  1136. int
  1137. give_supplies(unit, amts, rslts)
  1138. Unit *unit;
  1139. short *amts, *rslts;
  1140. {
  1141.     int m, gift, maxgift, actual, didsome;
  1142.     Unit *unit2;
  1143.  
  1144.     didsome = FALSE;
  1145.     unit2 = unit->transport;
  1146.     if (!(in_play(unit2) && completed(unit2)))
  1147.       return didsome;
  1148.     for_all_material_types(m) {
  1149.     if (rslts) rslts[m] = 0;
  1150.     maxgift = min(unit->supply[m], um_storage_x(unit2->type, m) - unit2->supply[m]);
  1151.     gift = ((amts == NULL || amts[m] == -1) ? (maxgift / 2) : amts[m]);
  1152.     if (gift > 0) {
  1153.         if (1 /* can do immed transfer */) {
  1154.         /* Be stingy if giver is low */
  1155.         if (2 * unit->supply[m] < um_storage_x(unit->type, m))
  1156.           gift = max(1, gift/2);
  1157.         actual = transfer_supply(unit, unit2, m, gift);
  1158.         if (rslts)
  1159.           rslts[m] = actual;
  1160.         if (actual > 0)
  1161.           didsome = TRUE;
  1162.         }
  1163.     }
  1164.     }
  1165.     return didsome;
  1166. }
  1167.  
  1168. int
  1169. take_supplies(unit, amts, rslts)
  1170. Unit *unit;
  1171. short *amts, *rslts;
  1172. {
  1173.     int m, want, actual, didsome;
  1174.     Unit *unit2;
  1175.  
  1176.     didsome = FALSE;
  1177.     for_all_material_types(m) {
  1178.     if (rslts) rslts[m] = 0;
  1179.     want = ((amts == NULL || amts[m] == -1)
  1180.             ? (um_storage_x(unit->type, m) - unit->supply[m])
  1181.             : amts[m]);
  1182.     if (want > 0) {
  1183.         unit2 = unit->transport;
  1184.         if (in_play(unit2) && completed(unit2)) {
  1185.         /* Be stingy if transport is low */
  1186.         if (2 * unit2->supply[m] < um_storage_x(unit2->type, m))
  1187.           want = max(1, want/2);
  1188.         actual = transfer_supply(unit2, unit, m, want);
  1189.         if (rslts)
  1190.           rslts[m] = actual;
  1191.         if (actual > 0)
  1192.           didsome = TRUE;
  1193.         }
  1194.     }
  1195.     }
  1196.     return didsome;
  1197. }
  1198.  
  1199. /* Generic image setup. */
  1200.  
  1201. static ImageFamily *
  1202. get_generic_images(side, name, interp_hook, load_hook)
  1203. Side *side;
  1204. char *name;
  1205. void (*interp_hook) PROTO ((ImageFamily *imf));
  1206. void (*load_hook) PROTO ((ImageFamily *imf));
  1207. {
  1208.     FILE *fp;
  1209.     int cloned = FALSE;
  1210.     ImageFamily *imf;
  1211.  
  1212.     imf = get_imf(name);
  1213.     if (imf == NULL)
  1214.       return NULL;
  1215.     if (imf->numsizes > 0)
  1216.       if (interp_hook != NULL) {
  1217.       imf = clone_imf(imf);
  1218.       cloned = TRUE;
  1219.       (*interp_hook)(imf);
  1220.       }
  1221.     if (load_hook != NULL) {
  1222.     if (!cloned) {
  1223.         imf = clone_imf(imf);
  1224.         cloned = TRUE;
  1225.     }
  1226.     (*load_hook)(imf);
  1227.     }
  1228.     if (imf->numsizes == 0) {
  1229.     /* Collect the names/locations of all image families. */
  1230.     fp = open_library_file("imf.dir");
  1231.     if (fp != NULL) {
  1232.         load_image_families(fp, FALSE, NULL);
  1233.         fclose(fp);
  1234.     } else {
  1235.         init_warning("Cannot open \"%s\", will not use it", "imf.dir");
  1236.     }
  1237.     /* Get a (possibly empty) family. */
  1238.     imf = get_imf(name);
  1239.     if (imf == NULL)
  1240.       return NULL;
  1241.     if (imf->location != NULL) {
  1242.         /* Load data filling in the family. */
  1243.         make_pathname(xconqlib, imf->location->name, "", spbuf);
  1244.         if (load_imf_file(spbuf, NULL)) {
  1245.         } else if (load_imf_file(imf->location->name, NULL)) {
  1246.         } else {
  1247.         /* complain here, or not? */
  1248.         }
  1249.         if (interp_hook != NULL) {
  1250.         imf = clone_imf(imf);
  1251.         cloned = TRUE;
  1252.         (*interp_hook)(imf);
  1253.         }
  1254.     }
  1255.     }
  1256.     return imf;
  1257. }
  1258.  
  1259. ImageFamily *
  1260. get_unit_type_images(side, u, interp_hook, load_hook, default_hook)
  1261. Side *side;
  1262. int u;
  1263. void (*interp_hook) PROTO ((ImageFamily *imf));
  1264. void (*load_hook) PROTO ((ImageFamily *imf));
  1265. void (*default_hook) PROTO ((ImageFamily *imf, int n, char *name));
  1266. {
  1267.     char *name;
  1268.     ImageFamily *imf;
  1269.  
  1270.     if (!empty_string(u_image_name(u)))
  1271.       name = u_image_name(u);
  1272.     else
  1273.       name = u_internal_name(u);
  1274.     imf = get_generic_images(side, name, interp_hook, load_hook);
  1275.     if (imf != NULL && imf->numsizes == 0 && default_hook != NULL) {
  1276.     imf->ersatz = TRUE;
  1277.     (*default_hook)(imf, u, u_type_name(u));
  1278.     }
  1279.     return imf;
  1280. }
  1281.  
  1282. ImageFamily *
  1283. get_terrain_type_images(side, t, interp_hook, load_hook, default_hook)
  1284. Side *side;
  1285. int t;
  1286. void (*interp_hook) PROTO ((ImageFamily *imf));
  1287. void (*load_hook) PROTO ((ImageFamily *imf));
  1288. void (*default_hook) PROTO ((ImageFamily *imf, int n, char *name));
  1289. {
  1290.     char *name;
  1291.     ImageFamily *imf;
  1292.  
  1293.     if (!empty_string(t_image_name(t)))
  1294.       name = t_image_name(t);
  1295.     else
  1296.       name = t_type_name(t);
  1297.     imf = get_generic_images(side, name, interp_hook, load_hook);
  1298.     if (imf != NULL && imf->numsizes == 0 && default_hook != NULL) {
  1299.     imf->ersatz = TRUE;
  1300.     (*default_hook)(imf, t, t_type_name(t));
  1301.     }
  1302.     return imf;
  1303. }
  1304.  
  1305. ImageFamily *
  1306. get_unseen_images(side, interp_hook, load_hook, default_hook)
  1307. Side *side;
  1308. void (*interp_hook) PROTO ((ImageFamily *imf));
  1309. void (*load_hook) PROTO ((ImageFamily *imf));
  1310. void (*default_hook) PROTO ((ImageFamily *imf, char *name));
  1311. {
  1312.     if (!empty_string(g_unseen_image_name())) {
  1313.     unseen_image = get_generic_images(side, g_unseen_image_name(), interp_hook, load_hook); 
  1314.     if (unseen_image != NULL && unseen_image->numsizes == 0) {
  1315.         /* Appears to have failed - clear the unseen image then. */
  1316.         unseen_image = NULL;
  1317.         /* Note that we shouldn't try to free the imf, because it may be use
  1318.            elsewhere. */
  1319.     }
  1320.     }
  1321.     return unseen_image;
  1322. }
  1323.  
  1324. ImageFamily *
  1325. get_emblem_images(side, side2, interp_hook, load_hook, default_hook)
  1326. Side *side, *side2;
  1327. void (*interp_hook) PROTO ((ImageFamily *imf));
  1328. void (*load_hook) PROTO ((ImageFamily *imf));
  1329. void (*default_hook) PROTO ((ImageFamily *imf, int n, char *name));
  1330. {
  1331.     char *name, tmpbuf[BUFSIZE];
  1332.     int s2 = side_number(side2);
  1333.     ImageFamily *imf;
  1334.  
  1335.     if (side2 != NULL && !empty_string(side2->emblemname))
  1336.       name = side2->emblemname;
  1337.     else {
  1338.     sprintf(tmpbuf, "s%d", s2);
  1339.     name = copy_string(tmpbuf);
  1340.     }
  1341.     imf = get_generic_images(side, name, interp_hook, load_hook);
  1342.     if (imf != NULL && imf->numsizes == 0 && default_hook != NULL && strcmp(name, "none") != 0) {
  1343.     (*default_hook)(imf, s2, name);
  1344.     }
  1345.     return imf;
  1346. }
  1347.